// Copyright 2012 dmitry.a.novikov@gmail.com
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
// http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// CnsZ::ValueString declaration


#ifndef _INCLUDED_CNZ_VALUESTRING_H_
#define _INCLUDED_CNZ_VALUESTRING_H_


namespace CnsZ {

  class String;

  class ValueStringHeader : public Object {
  protected:
    size_t len;
  };

  class ValueString : public Object {
  protected:
    size_t len;
    wchar_t buffer[1];
  protected:
    ValueString() : len(0) { buffer[0]=0; }
    ValueString(size_t l) : len(l) {}
  public:
    DECLARE_CNSZ_CLASS(ValueString);

    size_t length() const { return len; }

    const wchar_t* chars() const { return buffer; }

    int compare(const Object* other) const;

    String toString() const;

    static const ValueString* Empty();

    static String New(const ValueString* string);
    static String New(const wchar_t* string);
    static String New(const wchar_t* string, size_t len);
  };

  class String : public P<ValueString> {
  public:
    String();
    String(const ValueString* d) : P<ValueString>(d) {}
    String(const wchar_t* string);
    String(const wchar_t* uChars, size_t len);

    size_t length() const;
    const wchar_t* chars() const;
    operator const wchar_t*() const;

    String& operator=(const ValueString* string);
    bool operator==(const wchar_t* string) const;
    bool operator==(const ValueString*  string) const;
    bool operator <(const wchar_t* string) const;
    bool operator <(const ValueString*  string) const;
    bool operator >(const wchar_t* string) const;
    bool operator >(const ValueString*  string) const;

    String operator +(const ValueString* string) const;
  };


  class AString;

  class ValueAString : public Object {
  protected:
    size_t len;
    char buffer[1];
  protected:
    ValueAString() : len(0) { buffer[0]=0; }
    ValueAString(size_t l) : len(l) {}
  public:
    DECLARE_CNSZ_CLASS(ValueAString);

    size_t length() const { return len; }

    const char* chars() const { return buffer; }

    int compare(const Object* other) const;

    String toString() const;

    static const ValueAString* Empty();

    static AString New(const ValueAString* string);
    static AString New(const char* string);
    static AString New(const char* string, size_t len);
  };

  class AString : public P<ValueAString> {
  public:
    AString();
    AString(const ValueAString* d) : P<ValueAString>(d) {}
    AString(const char* string);
    AString(const char* uChars, size_t len);

    size_t length() const;
    const char* chars() const;
    operator const char*() const;

    AString& operator=(const ValueAString* string);
    bool operator==(const char* string) const;
    bool operator==(const ValueAString*  string) const;
    bool operator <(const char* string) const;
    bool operator <(const ValueAString*  string) const;
    bool operator >(const char* string) const;
    bool operator >(const ValueAString*  string) const;

    AString operator +(const ValueAString* string) const;
  };

  inline String ValueString::New(const ValueString* string) {
    return New(string->chars(), string->length());
  }

  inline String::String()
    : P<ValueString>(ValueString::Empty()) {
  }
  
  inline String::String(const wchar_t* string)
    : P<ValueString>(ValueString::New(string)) {
  }

  inline String::String(const wchar_t* string, size_t len)
    : P<ValueString>(ValueString::New(string, len)) {
  }

  inline String& String::operator=(const ValueString* string) {
    return static_cast<String&>(P<ValueString>::operator=(string));
  }

  inline bool String::operator==(const ValueString* string) const {
    return operator==(string->chars());
  }

  inline bool String::operator<(const ValueString* string) const {
    return operator<(string->chars());
  }

  inline bool String::operator>(const ValueString* string) const {
    return operator>(string->chars());
  }

  inline const wchar_t* String::chars() const {
    return get()->chars();
  }

  inline String::operator const wchar_t*() const {
     return chars();
  }

  inline size_t String::length() const {
    return get()->length();
  }


  inline AString ValueAString::New(const ValueAString* string) {
    return New(string->chars(), string->length());
  }

  inline AString::AString()
    : P<ValueAString>(ValueAString::Empty()) {
  }
  
  inline AString::AString(const char* string)
    : P<ValueAString>(ValueAString::New(string)) {
  }

  inline AString::AString(const char* string, size_t len)
    : P<ValueAString>(ValueAString::New(string, len)) {
  }

  inline AString& AString::operator=(const ValueAString* string) {
    return static_cast<AString&>(P<ValueAString>::operator=(string));
  }

  inline bool AString::operator==(const ValueAString* string) const {
    return operator==(string->chars());
  }

  inline bool AString::operator<(const ValueAString* string) const {
    return operator<(string->chars());
  }

  inline bool AString::operator>(const ValueAString* string) const {
    return operator>(string->chars());
  }

  inline const char* AString::chars() const {
    return get()->chars();
  }

  inline AString::operator const char*() const {
     return chars();
  }

  inline size_t AString::length() const {
    return get()->length();
  }

} //namespace CnsZ

inline std::wostream&
operator<<(std::wostream& ostr, const CnsZ::ValueString* string) {
  return ostr << string->chars();
}

#define CNSZ_DEFINE_STATIC_STRING(STRING_VAR_NAME,CONTENT) \
  class StaticClassFor_##STRING_VAR_NAME##_ : public ValueString {\
  protected:\
    StaticClassFor_##STRING_VAR_NAME##_() : ValueString((sizeof(CONTENT)-1)/sizeof(wchar_t)){}\
    struct Placeholder {\
      char padding[sizeof(CnsZ::ValueStringHeader)];\
      wchar_t buffer[sizeof(CONTENT)];\
    };\
  public:\
    static const String& getString() {\
      static Placeholder placeholder = {"",CONTENT};\
      static ValueString* s = new (&placeholder) ImplNoRefCount<StaticClassFor_##STRING_VAR_NAME##_>;\
      return *((const String*)&s);\
    }\
  }

#define CNSZ_DEFINE_STATIC_ASTRING(STRING_VAR_NAME,CONTENT) \
  class StaticClassFor_##STRING_VAR_NAME##_ : public ValueAString {\
  protected:\
    StaticClassFor_##STRING_VAR_NAME##_() : ValueAString(sizeof(CONTENT)-1){}\
    struct Placeholder {\
      char padding[sizeof(CnsZ::ValueStringHeader)];\
      char buffer[sizeof(CONTENT)];\
    };\
  public:\
    static const AString& getString() {\
      static Placeholder placeholder = {"",CONTENT};\
      static ValueAString* s = new (&placeholder) ImplNoRefCount<StaticClassFor_##STRING_VAR_NAME##_>;\
      return *((const AString*)&s);\
    }\
  }

#define CNSZ_GET_STATIC_STRING(STRING_VAR_NAME) StaticClassFor_##STRING_VAR_NAME##_::getString()

#define CNSZ_GET_STATIC_ASTRING(STRING_VAR_NAME) StaticClassFor_##STRING_VAR_NAME##_::getString()

#endif //#ifndef _INCLUDED_CNZ_VALUESTRING_H_